//!
//! 
//!  [`World`] 代表着 ecs 世界, 包含所有的系统、实体、组件
//! 
//!  [`Archetype`] 是具有相同组件类型的 [`Entity`] 的集合
//! 
//!  [`Entities`] 是实体到[`Archetype`]的映射
//! 
//! 
//! 
//! 
use std::collections::HashMap;

use crate::{archetype::Archetype, component::ComponentId, storage::StorageLookup, entity::{Entities, Entity, EntityLocation, self}, ComponentBundleTrait, ComponentTrait, MangoEcsError};



pub struct World {
    pub(crate) archetypes:Vec<Archetype>,
    /// 用于寻找具有 一组 组件id 的 Archetype
    pub(crate) components_ids_to_archetype_index:HashMap<Vec<ComponentId>,usize>,
    pub(crate) storage_lookup:StorageLookup,
    pub(crate) entities:Entities
}

struct RemoveInfo {
    archetype_index:usize,
    archetype_channel:usize,
    entity_index_in_archetype:usize
}

impl Default for World {
    fn default() -> Self {
        Self::new()
    }
}

impl World {
    pub fn new() -> Self {
        let mut world = Self {
            archetypes:vec![],
            components_ids_to_archetype_index:HashMap::new(),
            storage_lookup:StorageLookup::default(),
            entities:Entities::default()
        };

        // 插入不存在组件的实体类型
        world.archetypes.push(Archetype::new(0));
        world.storage_lookup.new_archetype(0, &[]);
        world.components_ids_to_archetype_index.insert(Vec::new(),0);
        world

    }

    pub fn is_empty(&self) -> bool {
        self.entities.len() != 0
    }

    pub fn len(&self) -> usize {
        self.entities.len()
    }


    pub(crate) fn migrate_entity(
        source_archetype:&mut Archetype,
        destination_archetype:&mut Archetype,
        entities:&mut Entities,
        entity:Entity,
        index_within_archetype:usize
    ) {
        if !source_archetype.channels.is_empty() &&
        !destination_archetype.channels.is_empty() {
            let mut source_channel_index = 0;
            let mut dest_channel_index = 0;
            let source_channel_len = source_archetype.channels.len();
            let dest_channel_len = destination_archetype.channels.len();

            while source_channel_index != source_channel_len && dest_channel_index != dest_channel_len {
                let source_channel = &mut source_archetype.channels[source_channel_index];
                let dest_channel = &mut destination_archetype.channels[dest_channel_index];

                match source_channel.component_id.cmp(&dest_channel.component_id) {
                    std::cmp::Ordering::Equal => {
                        source_channel.data.migrate_component(index_within_archetype, &mut *dest_channel.data);
                        source_channel_index += 1;
                        dest_channel_index += 1;
                    },
                    std::cmp::Ordering::Less => {
                        source_channel_index += 1;
                    },
                    std::cmp::Ordering::Greater => {
                        dest_channel_index += 1;
                    },
                }

            }
        }

        source_archetype.entities.swap_remove(index_within_archetype);
        destination_archetype.entities.push(entity);

        // 
        if let Some(swapped_entity) = source_archetype.entities.get(index_within_archetype) {
            entities.get_entity_location_mut(*swapped_entity)
            .as_mut()
            .unwrap()
            .index_within_archetype = index_within_archetype;
        }


        *entities.get_entity_location_mut(entity) = Some(EntityLocation {
            archetype_index: destination_archetype.index_in_world,
            index_within_archetype:destination_archetype.entities.len() - 1,
        })
    }

    pub(crate) fn spawn_reserved_entities(&mut self) {
        let empty_archetype = &mut self.archetypes[0];
        while let Some(entity) = self.entities
            .instantiate_reserved_entity(empty_archetype.entities.len()) {
            empty_archetype.entities.push(entity);
        }
    }

    ///
    /// 
    /// 通过一组[`Component`]创建一个[`Entity`]
    /// 这里有些问题
    /// 首先这里会先将实体移动到空组件的 [`Archetype`] 中
    /// 再将实体从空[`Archetype`]移动到正确的[`Archetype`]
    /// 目前之所以这样做是为了复用代码
    pub fn spawn<Bundle:ComponentBundleTrait>(
        &mut self,
        bundle:Bundle
    ) -> Entity {
        self.spawn_reserved_entities();
        let entity = self.entities.new_entity(Some(EntityLocation {
            archetype_index: 0,
            index_within_archetype: self.archetypes[0].entities.len(),
        }));

        self.archetypes[0].entities.push(entity);
        bundle.add_to_entity(self, entity).unwrap();
        entity
        
    }

    pub fn add_component<C:ComponentTrait>(
        &mut self,
        entity:Entity,
        component:C
    ) -> Result<(),MangoEcsError> {
        self.spawn_reserved_entities();
        (component,).add_to_entity(self, entity)
    }

}







mod test {
    use crate::{ComponentTrait, World};

    #[test]
    fn test_spawn(){
        struct Name(String);
        
        impl ComponentTrait for Name {}
        
        struct Age(u32);
        impl ComponentTrait for Age {}

        let mut world = World::default();

        let entity = world.spawn(Name("Mango Ecs".to_owned()));

        println!("entity ={:?}",entity);
        
        assert!(world.len() == 1);
        
        let entity = world.spawn((Name("entity 1".to_owned()),Age(10)));
        println!("entity ={:?}",entity);
        assert!(world.len() == 2);


    }
}









